package nape.geom;
import zpp_nape.Config;
import zpp_nape.Const;
import zpp_nape.util.Flags;
import DummyNapeMain;
import zpp_nape.util.Math;
import zpp_nape.util.Names;
import zpp_nape.util.Pool;
import zpp_nape.util.Lists;
import zpp_nape.shape.Circle;
import zpp_nape.shape.Edge;
import zpp_nape.space.Space;
import zpp_nape.shape.Polygon;
import zpp_nape.shape.Shape;
import zpp_nape.phys.FeatureMix;
import zpp_nape.phys.FluidProperties;
import zpp_nape.phys.Material;
import zpp_nape.phys.Body;
import zpp_nape.geom.AABB;
import zpp_nape.geom.Distance;
import zpp_nape.geom.Mat23;
import zpp_nape.geom.Vec2;
import zpp_nape.geom.VecMath;
import zpp_nape.geom.Collide;
import zpp_nape.dynamics.Arbiter;
import zpp_nape.dynamics.Contact;
import zpp_nape.dynamics.InteractionFilter;
import zpp_nape.constraint.Constraint;
import zpp_nape.dynamics.SpaceArbiterList;
import zpp_nape.constraint.Matrices;
import zpp_nape.constraint.PivotJoint;
import zpp_nape.constraint.WeldJoint;
import nape.util.Flags;
import nape.util.Lists;
import nape.util.Debug;
import nape.space.Space;
import nape.shape.Circle;
import nape.shape.Polygon;
import nape.shape.Edge;
import nape.shape.Shape;
import nape.phys.FluidProperties;
import nape.phys.Material;
import nape.phys.Body;
import nape.geom.AABB;
import nape.geom.Geom;
import nape.geom.Mat23;
import nape.dynamics.Contact;
import nape.dynamics.Arbiter;
import nape.dynamics.InteractionFilter;
#if swc@:keep#end class Vec2List{
    public var zpp_inner:ZPP_Vec2List;
    public var length(flibget_length,never):Int;
    #if false inline function flibget_length(){
        zpp_inner.valmod();
        if(zpp_inner.zip_length){
            zpp_inner.zip_length=false;
            if(false){
                zpp_inner.user_length=0;
                {
                    var cx_ite=zpp_inner.inner.begin();
                    while(cx_ite!=null){
                        var i=cx_ite.elem();
                        if(true)zpp_inner.user_length++;
                        cx_ite=cx_ite.next;
                    }
                };
            }
            else zpp_inner.user_length=zpp_inner.length;
        }
        return zpp_inner.user_length;
    }
    #else inline function flibget_length(){
        return zpp_gl();
    }
    public function zpp_gl(){
        zpp_inner.valmod();
        if(zpp_inner.zip_length){
            zpp_inner.zip_length=false;
            if(false){
                zpp_inner.user_length=0;
                {
                    var cx_ite=zpp_inner.inner.begin();
                    while(cx_ite!=null){
                        var i=cx_ite.elem();
                        if(true)zpp_inner.user_length++;
                        cx_ite=cx_ite.next;
                    }
                };
            }
            else zpp_inner.user_length=zpp_inner.length;
        }
        return zpp_inner.user_length;
    }
    public function zpp_vm(){
        zpp_inner.valmod();
    }
    #end#if swc@:keep#end public static function fromArray(array:#if flash9 Array<Dynamic>#else Array<Vec2>#end){
        var ret=new Vec2List();
        for(i in array){
            #if flash9 if(!Std.is(i,Vec2))throw "Error: Array contains non "+"Vec2"+" types.";
            #end ret.push(i);
        }
        return ret;
    }
    #if flash9#if swc@:keep#end public static function fromVector(vector:flash.Vector<Vec2>){
        var ret=new Vec2List();
        for(i in vector)ret.push(i);
        return ret;
    }
    #end#if swc@:keep#end public function at(index:Int):Vec2{
        #if false zpp_inner.valmod();
        #else zpp_vm();
        #end if(index<0||index>=length)throw "Error: Index out of bounds";
        if(zpp_inner.reverse_flag)index=(length-1-index);
        if(!false){
            if(index<zpp_inner.at_index||zpp_inner.at_ite==null){
                zpp_inner.at_index=index;
                zpp_inner.at_ite=zpp_inner.inner.iterator_at(index);
            }
            else{
                while(zpp_inner.at_index!=index){
                    zpp_inner.at_index++;
                    zpp_inner.at_ite=zpp_inner.at_ite.next;
                }
            }
        }
        else{
            if(index<zpp_inner.at_index||zpp_inner.at_ite==null){
                zpp_inner.at_index=0;
                zpp_inner.at_ite=zpp_inner.inner.begin();
                while(true){
                    var x=zpp_inner.at_ite.elem();
                    if(true)break;
                    zpp_inner.at_ite=zpp_inner.at_ite.next;
                }
            }
            while(zpp_inner.at_index!=index){
                zpp_inner.at_index++;
                zpp_inner.at_ite=zpp_inner.at_ite.next;
                while(true){
                    var x=zpp_inner.at_ite.elem();
                    if(true)break;
                    zpp_inner.at_ite=zpp_inner.at_ite.next;
                }
            }
        }
        return zpp_inner.at_ite.elem().wrapper();
    }
    #if swc@:keep#end public function push(obj:Vec2){
        if(zpp_inner.immutable)throw "Error: "+"Vec2"+"List is immutable";
        zpp_inner.modify_test();
        #if false zpp_inner.valmod();
        #else zpp_vm();
        #end var cont=if(zpp_inner.adder!=null)zpp_inner.adder(obj)else true;
        if(cont){
            if(zpp_inner.reverse_flag)zpp_inner.inner.add(obj.zpp_inner);
            else{
                if(zpp_inner.push_ite==null)zpp_inner.push_ite=empty()?null:zpp_inner.inner.iterator_at(length-1);
                zpp_inner.push_ite=zpp_inner.inner.insert(zpp_inner.push_ite,obj.zpp_inner);
            }
            zpp_inner.invalidate();
            if(zpp_inner.post_adder!=null)zpp_inner.post_adder(obj);
        }
        return cont;
    }
    #if swc@:keep#end public function unshift(obj:Vec2){
        if(zpp_inner.immutable)throw "Error: "+"Vec2"+"List is immutable";
        zpp_inner.modify_test();
        #if false zpp_inner.valmod();
        #else zpp_vm();
        #end var cont=if(zpp_inner.adder!=null)zpp_inner.adder(obj)else true;
        if(cont){
            if(zpp_inner.reverse_flag){
                if(zpp_inner.push_ite==null)zpp_inner.push_ite=empty()?null:zpp_inner.inner.iterator_at(length-1);
                zpp_inner.push_ite=zpp_inner.inner.insert(zpp_inner.push_ite,obj.zpp_inner);
            }
            else zpp_inner.inner.add(obj.zpp_inner);
            zpp_inner.invalidate();
            if(zpp_inner.post_adder!=null)zpp_inner.post_adder(obj);
        }
        return cont;
    }
    #if swc@:keep#end public function pop():Vec2{
        if(zpp_inner.immutable)throw "Error: "+"Vec2"+"List is immutable";
        zpp_inner.modify_test();
        if(empty())throw "Error: Cannot remove from empty list";
        #if false zpp_inner.valmod();
        #else zpp_vm();
        #end var ret=null;
        if(zpp_inner.reverse_flag){
            ret=zpp_inner.inner.front();
            var retx=ret.wrapper();
            if(zpp_inner.subber!=null)zpp_inner.subber(retx);
            zpp_inner.inner.pop();
        }
        else{
            if(zpp_inner.at_ite!=null&&zpp_inner.at_ite.next==null)zpp_inner.at_ite=null;
            var ite=length==1?null:zpp_inner.inner.iterator_at(length-2);
            ret=ite==null?zpp_inner.inner.front():ite.next.elem();
            var retx=ret.wrapper();
            if(zpp_inner.subber!=null)zpp_inner.subber(retx);
            zpp_inner.inner.erase(ite);
        }
        zpp_inner.invalidate();
        var retx=ret.wrapper();
        return retx;
    }
    #if swc@:keep#end public function shift():Vec2{
        if(zpp_inner.immutable)throw "Error: "+"Vec2"+"List is immutable";
        zpp_inner.modify_test();
        if(empty())throw "Error: Cannot remove from empty list";
        #if false zpp_inner.valmod();
        #else zpp_vm();
        #end var ret=null;
        if(zpp_inner.reverse_flag){
            if(zpp_inner.at_ite!=null&&zpp_inner.at_ite.next==null)zpp_inner.at_ite=null;
            var ite=length==1?null:zpp_inner.inner.iterator_at(length-2);
            ret=ite==null?zpp_inner.inner.front():ite.next.elem();
            var retx=ret.wrapper();
            if(zpp_inner.subber!=null)zpp_inner.subber(retx);
            zpp_inner.inner.erase(ite);
        }
        else{
            ret=zpp_inner.inner.front();
            var retx=ret.wrapper();
            if(zpp_inner.subber!=null)zpp_inner.subber(retx);
            zpp_inner.inner.pop();
        }
        zpp_inner.invalidate();
        var retx=ret.wrapper();
        return retx;
    }
    #if swc@:keep#end public function add(obj:Vec2)return if(zpp_inner.reverse_flag)push(obj)else unshift(obj)#if swc@:keep#end public function remove(obj:Vec2):Bool{
        if(zpp_inner.immutable)throw "Error: "+"Vec2"+"List is immutable";
        zpp_inner.modify_test();
        #if false zpp_inner.valmod();
        #else zpp_vm();
        #end var ret=({
            var ret=false;
            {
                var cx_ite=zpp_inner.inner.begin();
                while(cx_ite!=null){
                    var x=cx_ite.elem();
                    {
                        if(x==obj.zpp_inner){
                            ret=true;
                            break;
                        }
                    };
                    cx_ite=cx_ite.next;
                }
            };
            ret;
        });
        if(ret){
            if(zpp_inner.subber!=null)zpp_inner.subber(obj);
            zpp_inner.inner.remove(obj.zpp_inner);
            zpp_inner.invalidate();
        }
        return ret;
    }
    #if swc@:keep#end public function empty(){
        #if false if(false)return length==0;
        else return zpp_inner.inner.empty();
        #else return length==0;
        #end
    }
    #if swc@:keep#end public function iterator(){
        #if false zpp_inner.valmod();
        #else zpp_vm();
        #end if(zpp_inner.iterators==null)zpp_inner.iterators=new ZNPList_Vec2Iterator();
        return Vec2Iterator.get(this);
    }
    #if swc@:keep#end public function copy(?deep:Bool=false){
        var ret=new Vec2List();
        for(i in this)ret.push(deep?i.copy():i);
        return ret;
    }
    public function new(){
        zpp_inner=new ZPP_Vec2List();
        zpp_inner.outer=this;
    }
    @:keep public function toString(){
        var ret="[";
        var fst=true;
        for(i in this){
            if(!fst)ret+=",";
            ret+=i.toString();
            fst=false;
        }
        return ret+"]";
    }
}
#if swc@:keep#end class Vec2Iterator{
    public var zpp_inner:Vec2List;
    public var zpp_i:Int;
    public var zpp_critical:Bool;
    public static var zpp_pool:Vec2Iterator;
    public var zpp_next:Vec2Iterator;
    public function new(){
        if(!ZPP_Vec2List.internal)throw "Error: Cannot instantiate "+"Vec2"+"Iterator derp!";
    }
    public static inline function get(list:Vec2List){
        var ret=if(zpp_pool==null){
            ZPP_Vec2List.internal=true;
            var ret=new Vec2Iterator();
            ZPP_Vec2List.internal=false;
            ret;
        }
        else{
            var r=zpp_pool;
            zpp_pool=r.zpp_next;
            r;
        }
        ret.zpp_i=0;
        ret.zpp_inner=list;
        ret.zpp_critical=false;
        list.zpp_inner.iterators.add(ret);
        return ret;
    }
    #if swc@:keep#end public inline function hasNext(){
        #if true zpp_inner.zpp_inner.valmod();
        #else zpp_inner.zpp_vm();
        #end var length=zpp_inner.length;
        zpp_critical=true;
        if(zpp_i<length){
            return true;
        }
        else{
            zpp_next=zpp_pool;
            zpp_pool=this;
            zpp_inner.zpp_inner.iterators.remove(this);
            return false;
        }
    }
    #if swc@:keep#end public inline function next(){
        zpp_critical=false;
        return zpp_inner.at(zpp_i++);
    }
}
#if swc@:keep#end class Vec2{
    public var zpp_inner:ZPP_Vec2;
    public function new(?x:Float=0,?y:Float=0){
        if(({
            #if flash9 var ret:Bool=untyped __global__["isNaN"](x);
            ret;
            #else Math.isNaN(x);
            #end
        })||({
            #if flash9 var ret:Bool=untyped __global__["isNaN"](y);
            ret;
            #else Math.isNaN(y);
            #end
        }))throw "Error: Vec2 components cannot be NaN";
        zpp_inner=ZPP_Vec2.get(x,y);
        zpp_inner.outer=this;
    }
    #if swc@:keep#end public inline function copy()return new Vec2(x,y)#if flash9#if swc@:keep#end public static inline function fromPoint(point:flash.geom.Point){
        if(point==null)throw "Error: Cannot create Vec2 from null Point object";
        if(({
            #if flash9 var ret:Bool=untyped __global__["isNaN"](point.x);
            ret;
            #else Math.isNaN(point.x);
            #end
        })||({
            #if flash9 var ret:Bool=untyped __global__["isNaN"](point.y);
            ret;
            #else Math.isNaN(point.y);
            #end
        }))throw "Error: Error: Vec2 components cannot be NaN";
        return new Vec2(point.x,point.y);
    }
    #end#if swc@:keep#end public static inline function fromPolar(length:Float,angle:Float){
        if(({
            #if flash9 var ret:Bool=untyped __global__["isNaN"](length);
            ret;
            #else Math.isNaN(length);
            #end
        }))throw "Error: Vec2::length cannot be NaN";
        if(({
            #if flash9 var ret:Bool=untyped __global__["isNaN"](angle);
            ret;
            #else Math.isNaN(angle);
            #end
        }))throw "Error: Vec2::angle cannot be NaN";
        return new Vec2(length*Math.cos(angle),length*Math.sin(angle));
    }
    public var x(flibget_x,flibset_x):Float;
    inline function flibget_x(){
        zpp_inner.validate();
        return zpp_inner.x;
    }
    inline function flibset_x(x:Float){
        if(zpp_inner.immutable)throw "Error: Vec2 is immutable";
        if(zpp_inner._immutable!=null)zpp_inner._immutable();
        if(zpp_inner.x!=x){
            if(({
                #if flash9 var ret:Bool=untyped __global__["isNaN"](x);
                ret;
                #else Math.isNaN(x);
                #end
            }))throw "Error: Vec2::"+"x"+" cannot be NaN";
            zpp_inner.x=x;
            zpp_inner.invalidate();
        }
        return x;
    }
    public var y(flibget_y,flibset_y):Float;
    inline function flibget_y(){
        zpp_inner.validate();
        return zpp_inner.y;
    }
    inline function flibset_y(y:Float){
        if(zpp_inner.immutable)throw "Error: Vec2 is immutable";
        if(zpp_inner._immutable!=null)zpp_inner._immutable();
        if(zpp_inner.y!=y){
            if(({
                #if flash9 var ret:Bool=untyped __global__["isNaN"](y);
                ret;
                #else Math.isNaN(y);
                #end
            }))throw "Error: Vec2::"+"y"+" cannot be NaN";
            zpp_inner.y=y;
            zpp_inner.invalidate();
        }
        return y;
    }
    public var length(flibget_length,flibset_length):Float;
    inline function flibget_length()return Math.sqrt((this.x*this.x+this.y*this.y))inline function flibset_length(length:Float){
        if(zpp_inner.immutable)throw "Error: Vec2 is immutable";
        if(({
            #if flash9 var ret:Bool=untyped __global__["isNaN"](length);
            ret;
            #else Math.isNaN(length);
            #end
        }))throw "Error: Vec2::length cannot be NaN";
        {
            var t=(length/Math.sqrt((this.x*this.x+this.y*this.y)));
            {
                #if NAPE_ASSERT var res={
                    !({
                        #if flash9 var ret:Bool=untyped __global__["isNaN"](t);
                        ret;
                        #else Math.isNaN(t);
                        #end
                    });
                };
                if(!res)throw "assert("+"!assert_isNaN(t)"+") :: "+("vec_muleq(in a: "+"this."+",in s: "+"length/Math.sqrt((this.x*this.x+this.y*this.y))"+")");
                #end
            };
            this.x*=t;
            this.y*=t;
        };
        zpp_inner.invalidate();
        return length;
    }
    #if swc@:keep#end public inline function lsq()return(this.x*this.x+this.y*this.y)public inline function set(p:Vec2){
        if(zpp_inner.immutable)throw "Error: Vec2 is immutable";
        if(p==null)throw "Error: Cannot assign null Vec2";
        return setxy(p.x,p.y);
    }
    public inline function setxy(x:Float,y:Float){
        if(zpp_inner.immutable)throw "Error: Vec2 is immutable";
        if(({
            #if flash9 var ret:Bool=untyped __global__["isNaN"](x);
            ret;
            #else Math.isNaN(x);
            #end
        })||({
            #if flash9 var ret:Bool=untyped __global__["isNaN"](y);
            ret;
            #else Math.isNaN(y);
            #end
        }))throw "Error: Vec2 components cannot be NaN";
        {
            zpp_inner.x=x;
            zpp_inner.y=y;
            {
                #if NAPE_ASSERT var res={
                    !({
                        #if flash9 var ret:Bool=untyped __global__["isNaN"](zpp_inner.x);
                        ret;
                        #else Math.isNaN(zpp_inner.x);
                        #end
                    });
                };
                if(!res)throw "assert("+"!assert_isNaN(zpp_inner.x)"+") :: "+("vec_set(in n: "+"zpp_inner."+",in x: "+"x"+",in y: "+"y"+")");
                #end
            };
            {
                #if NAPE_ASSERT var res={
                    !({
                        #if flash9 var ret:Bool=untyped __global__["isNaN"](zpp_inner.y);
                        ret;
                        #else Math.isNaN(zpp_inner.y);
                        #end
                    });
                };
                if(!res)throw "assert("+"!assert_isNaN(zpp_inner.y)"+") :: "+("vec_set(in n: "+"zpp_inner."+",in x: "+"x"+",in y: "+"y"+")");
                #end
            };
        };
        zpp_inner.invalidate();
        return this;
    }
    public var angle(flibget_angle,flibset_angle):Float;
    inline function flibget_angle(){
        if(x==y&&x==0)return 0.0;
        else return Math.atan2(y,x);
    }
    inline function flibset_angle(angle:Float){
        if(zpp_inner.immutable)throw "Error: Vec2 is immutable";
        if(({
            #if flash9 var ret:Bool=untyped __global__["isNaN"](angle);
            ret;
            #else Math.isNaN(angle);
            #end
        }))throw "Error: Vec2::angle cannot be NaN";
        var l=length;
        setxy(l*Math.cos(angle),l*Math.sin(angle));
        return angle;
    }
    #if swc@:keep#end public inline function add(a:Vec2){
        if(a==null)throw "Error: Cannot add null vectors";
        return new Vec2(x+a.x,y+a.y);
    }
    #if swc@:keep#end public inline function sub(a:Vec2){
        if(a==null)throw "Error: Cannot subtract null vectors";
        return new Vec2(x-a.x,y-a.y);
    }
    #if swc@:keep#end public inline function mul(s:Float){
        if(({
            #if flash9 var ret:Bool=untyped __global__["isNaN"](s);
            ret;
            #else Math.isNaN(s);
            #end
        }))throw "Error: Cannot multiply with NaN";
        return new Vec2(x*s,y*s);
    }
    #if swc@:keep#end public inline function addeq(a:Vec2){
        if(zpp_inner.immutable)throw "Error: Vec2 is immutable";
        if(a==null)throw "Error: Cannot add null vectors";
        return setxy(x+a.x,y+a.y);
    }
    #if swc@:keep#end public inline function subeq(a:Vec2){
        if(zpp_inner.immutable)throw "Error: Vec2 is immutable";
        if(a==null)throw "Error: Cannot subtract null vectors";
        return setxy(x-a.x,y-a.y);
    }
    #if swc@:keep#end public inline function muleq(s:Float){
        if(zpp_inner.immutable)throw "Error: Vec2 is immutable";
        if(({
            #if flash9 var ret:Bool=untyped __global__["isNaN"](s);
            ret;
            #else Math.isNaN(s);
            #end
        }))throw "Error: Cannot multiply with NaN";
        return setxy(x*s,y*s);
    }
    #if swc@:keep#end public inline function dot(a:Vec2){
        if(a==null)throw "Error: Cannot take dot product with null vector";
        return(x*a.x+y*a.y);
    }
    #if swc@:keep#end public inline function cross(a:Vec2){
        if(a==null)throw "Error: Cannot take cross product with null vector";
        return(a.y*x-a.x*y);
    }
    @:keep public inline function toString(){
        zpp_inner.validate();
        return zpp_inner.toString();
    }
}
